home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / QuickTime VR / MacOS / QuickDraw™ 3D 1.0.6F4 SDK / Samples / SampleCode / View3DMF NetScape Plugin / View3DMF Plugin / MetaFileView.cp next >
Encoding:
Text File  |  1996-03-10  |  20.9 KB  |  718 lines  |  [TEXT/CWIE]

  1. //MetaFileView.cp
  2. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  3. //
  4. // Quickdraw 3D sample code
  5. //
  6. // Rick Evans, AppleLink: DEVSUPPORT (devsupport@applelink.apple.com)
  7. //
  8. // The following functions were adapted from the QD3D sample MetaFileRead.
  9. //
  10. // ©1996 Apple Computer Inc., All Rights Reserved
  11. //
  12. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  13.  
  14. // for QuickDraw 3D
  15. #include <QD3D.h>
  16. #include <QD3DMath.h>
  17. #include <QD3DDrawContext.h>
  18. #include <QD3DShader.h>
  19. #include <QD3DTransform.h>
  20. #include <QD3DGroup.h>
  21. #include <QD3DCamera.h>
  22. #include <QD3DErrors.h>
  23. #include <QD3DStyle.h>
  24. #include <QD3DView.h>
  25. #include <QD3DRenderer.h>
  26. #include <QD3DLight.h>
  27. #include <QD3DStorage.h>
  28. #include <QD3DIO.h>
  29.  
  30. #include "View3DMF.h"
  31. #include "MetaFileView.h"
  32.  
  33. //-----------------------------------------------------------------------------------------------
  34. // private prototypes:
  35. //-----------------------------------------------------------------------------------------------
  36. static TQ3DrawContextObject    MyNewDrawContext(WindowPtr theWindow, Rect* theRect) ;
  37. static TQ3FileObject         MyGetNewFile( PluginInstance* This ) ;
  38. static TQ3CameraObject        MyNewCamera(WindowPtr theWindow) ;
  39. static TQ3GroupObject        MyNewLights( void ) ;
  40. static TQ3Status            MyAddShaderToGroup( TQ3GroupObject group ) ;
  41. static TQ3Status            MyReadModelFromFile( TQ3FileObject theFile, TQ3GroupObject myGroup) ;
  42. static TQ3Status            SubmitScene( PluginInstance* theDocument ) ;
  43. static TQ3Status             GetDocumentGroupBoundingBox(PluginInstance*    t, TQ3BoundingBox *viewBBox) ;
  44. static void                 GetGroupBBox(PluginInstance* theDocument, TQ3BoundingBox *viewBBox) ;
  45. static char*                TypeNameFromQ3Obj(char* nm, TQ3Object obj) ;
  46. static char*                NameFromQ3Type(char* nm, TQ3ObjectType typ) ;
  47.  
  48.  
  49. //------------------------------------------------------------------------------------
  50. // MyNewView:
  51. //------------------------------------------------------------------------------------
  52.  
  53. TQ3ViewObject MyNewView(GrafPtr theWindow, Rect* theRect) 
  54. {
  55.     TQ3Status                myStatus;
  56.     TQ3ViewObject            myView;
  57.     TQ3DrawContextObject    myDrawContext;
  58.     TQ3RendererObject        myRenderer;
  59.     TQ3CameraObject            myCamera;
  60.     TQ3GroupObject            myLights;
  61.     
  62.     myView = ::Q3View_New();
  63.     if (myView == NULL)
  64.         goto bailnow;
  65.     
  66.     //    Create and set draw context.
  67.     if ((myDrawContext = MyNewDrawContext(theWindow, theRect)) == nil )
  68.         goto bail;
  69.         
  70.     myStatus = ::Q3View_SetDrawContext(myView, myDrawContext) ;
  71.  
  72.     ::Q3Object_Dispose( myDrawContext ) ;
  73.  
  74.     if (myStatus == kQ3Failure)
  75.         goto bail;
  76.     
  77.     // Create and set renderer.
  78.     //
  79.     // hacky way to do this, but since I wanted these snippets to have 
  80.     // a minimal interface, this will suffice
  81.     //
  82.     // change the next line to “#if 1” to use the WF renderer
  83.     
  84. #if 0
  85.  
  86.     // this would use the wireframe renderer
  87.     myRenderer = ::Q3Renderer_NewFromType(kQ3RendererTypeWireFrame) ;
  88.     if (myRenderer == NULL)
  89.         goto bail;
  90.  
  91. #else
  92.  
  93.     // this would use the interactive software renderer
  94.     myRenderer = ::Q3Renderer_NewFromType(kQ3RendererTypeInteractive) ;
  95.     if (myRenderer == NULL)
  96.         goto bail;
  97.  
  98. #endif
  99.  
  100.     myStatus = ::Q3View_SetRenderer(myView, myRenderer) ;
  101.  
  102.     ::Q3Object_Dispose( myRenderer ) ;
  103.  
  104.     if ( myStatus == kQ3Failure )
  105.         goto bail;
  106.     
  107.     //    Create and set camera.
  108.     myCamera = MyNewCamera(theWindow) ;
  109.     if (myCamera == NULL)
  110.         goto bail;
  111.         
  112.     myStatus = ::Q3View_SetCamera(myView, myCamera);
  113.  
  114.     ::Q3Object_Dispose( myCamera ) ;
  115.  
  116.     if ( myStatus == kQ3Failure )
  117.         goto bail;
  118.     
  119.     //    Create and set lights.
  120.     myLights = MyNewLights() ;
  121.     if (myLights == NULL)
  122.         goto bail;
  123.         
  124.     myStatus = ::Q3View_SetLightGroup(myView, myLights) ;
  125.         
  126.     ::Q3Object_Dispose(myLights);
  127.  
  128.     if ( myStatus == kQ3Failure )
  129.         goto bail;
  130.  
  131.     //    Done!!!
  132.     return ( myView );
  133.     
  134.     //    If any of the above failed, dispose the view object and return NULL.
  135. bail:
  136.     ::Q3Object_Dispose( myView ) ; // disposing view disposes all objects set in view
  137.  
  138. bailnow: 
  139.     return ( NULL );
  140. }
  141.  
  142. //------------------------------------------------------------------------------------
  143. // MyNewDrawContext:
  144. //------------------------------------------------------------------------------------
  145. TQ3DrawContextObject MyNewDrawContext(WindowPtr theWindow, Rect* theRect)
  146. {
  147.     //TQ3DrawContextData        myDrawContextData;
  148.     TQ3MacDrawContextData    myMacDrawContextData;
  149.     TQ3ColorARGB            ClearColor;
  150.     TQ3DrawContextObject    myDrawContext ;    
  151.     
  152.     ClearColor.a = 1.0;
  153.     ClearColor.r = 1.0;
  154.     ClearColor.g = 1.0;
  155.     ClearColor.b = 1.0;
  156.     
  157.     //    Fill in draw context data.
  158.     myMacDrawContextData.drawContextData.pane.min.x = theRect->left;
  159.     myMacDrawContextData.drawContextData.pane.min.y = theRect->top;
  160.     myMacDrawContextData.drawContextData.pane.max.x = theRect->right;
  161.     myMacDrawContextData.drawContextData.pane.max.y = theRect->bottom;
  162.     
  163.     myMacDrawContextData.drawContextData.clearImageMethod = kQ3ClearMethodWithColor;
  164.     myMacDrawContextData.drawContextData.clearImageColor = ClearColor;
  165.     
  166.     myMacDrawContextData.drawContextData.paneState = kQ3True;
  167.     myMacDrawContextData.drawContextData.maskState = kQ3False;
  168.     
  169.     myMacDrawContextData.drawContextData.doubleBufferState = kQ3True;
  170.     
  171.     myMacDrawContextData.window = (CGrafPtr) theWindow;        // this is the window associated with the view
  172.     myMacDrawContextData.library = kQ3Mac2DLibraryNone;
  173.     myMacDrawContextData.viewPort = nil;
  174.     myMacDrawContextData.grafPort = (CGrafPtr) theWindow;
  175.     
  176.     //    Create draw context and return it, if it’s nil the caller must handle
  177.     myDrawContext = ::Q3MacDrawContext_New(&myMacDrawContextData) ;
  178.  
  179.     return myDrawContext ;
  180. }
  181.  
  182. //------------------------------------------------------------------------------------
  183. // MyNewCamera:
  184. //------------------------------------------------------------------------------------
  185. TQ3CameraObject MyNewCamera(WindowPtr theWindow)
  186. {
  187.     TQ3CameraObject                    myCamera;
  188.     TQ3CameraData                    myCameraData;
  189.     TQ3ViewAngleAspectCameraData        myViewAngleCameraData;
  190.     TQ3Point3D                        cameraFrom     = { 0.0, 0.0, 30.0 };
  191.     TQ3Point3D                        cameraTo     = { 0.0, 0.0, 0.0 };
  192.     TQ3Vector3D                        cameraUp     = { 0.0, 1.0, 0.0 };
  193.     
  194.     float                             fieldOfView = .52359333333;
  195.     float                             hither         = 0.001;
  196.     float                             yon         = 1000;
  197.     
  198.     //    Fill in camera data.
  199.     myCameraData.placement.cameraLocation = cameraFrom;
  200.     myCameraData.placement.pointOfInterest = cameraTo;
  201.     myCameraData.placement.upVector = cameraUp;
  202.     
  203.     myCameraData.range.hither = hither;
  204.     myCameraData.range.yon = yon;
  205.     
  206.     myCameraData.viewPort.origin.x = -1.0;
  207.     myCameraData.viewPort.origin.y = 1.0;
  208.     myCameraData.viewPort.width = 2.0;
  209.     myCameraData.viewPort.height = 2.0;
  210.     
  211.     myViewAngleCameraData.cameraData = myCameraData;
  212.     myViewAngleCameraData.fov = fieldOfView ;
  213.     
  214.     // set up the aspect ratio based on the window
  215.     myViewAngleCameraData.aspectRatioXToY =  
  216.             (float) (theWindow->portRect.right - theWindow->portRect.left) / 
  217.             (float) (theWindow->portRect.bottom - theWindow->portRect.top);
  218.  
  219.     myCamera = ::Q3ViewAngleAspectCamera_New(&myViewAngleCameraData);    
  220.     
  221.     //    Return the camera.
  222.     return ( myCamera );
  223. }
  224.  
  225.  
  226. //------------------------------------------------------------------------------------
  227. // MyNewLights:
  228. //------------------------------------------------------------------------------------
  229. TQ3GroupObject MyNewLights()
  230. {
  231.     TQ3GroupPosition            myGroupPosition;
  232.     TQ3GroupObject            myLightList;
  233.     TQ3LightData                myLightData;
  234.     TQ3PointLightData        myPointLightData;
  235.     TQ3DirectionalLightData    myDirectionalLightData;
  236.     TQ3LightObject            myAmbientLight, myPointLight, myFillLight;
  237.     TQ3Point3D                pointLocation = { -10.0, 0.0, 10.0 };
  238.     TQ3Vector3D                fillDirection = { 10.0, 0.0, 10.0 };
  239.     TQ3ColorRGB                WhiteLight = { 1.0, 1.0, 1.0 };
  240.     
  241.     //    Set up light data for ambient light.  This light data will be used for point and fill
  242.     //    light also.
  243.  
  244.     myLightData.isOn = kQ3True;
  245.     myLightData.color = WhiteLight;
  246.     
  247.     //    Create ambient light.
  248.     myLightData.brightness = .2;
  249.     myAmbientLight = ::Q3AmbientLight_New(&myLightData);
  250.     if ( myAmbientLight == nil )
  251.         goto bail;
  252.     
  253.     //    Create point light.
  254.     myLightData.brightness = 1.0;
  255.     myPointLightData.lightData = myLightData;
  256.     myPointLightData.castsShadows = kQ3False;
  257.     myPointLightData.attenuation = kQ3AttenuationTypeNone;
  258.     myPointLightData.location = pointLocation;
  259.     myPointLight = ::Q3PointLight_New(&myPointLightData);
  260.     if ( myPointLight == nil )
  261.         goto bail;
  262.  
  263.     //    Create fill light.
  264.     myLightData.brightness = .2;
  265.     myDirectionalLightData.lightData = myLightData;
  266.     myDirectionalLightData.castsShadows = kQ3False;
  267.     myDirectionalLightData.direction = fillDirection;
  268.     myFillLight = ::Q3DirectionalLight_New(&myDirectionalLightData);
  269.     if ( myFillLight == nil )
  270.         goto bail;
  271.  
  272.     //    Create light group and add each of the lights into the group.
  273.     myLightList = Q3LightGroup_New();
  274.     if ( myLightList == nil )
  275.         goto bail;
  276.     myGroupPosition = ::Q3Group_AddObject(myLightList, myAmbientLight);
  277.     if ( myGroupPosition == 0 )
  278.         goto bail;
  279.     myGroupPosition = ::Q3Group_AddObject(myLightList, myPointLight);
  280.     if ( myGroupPosition == 0 )
  281.         goto bail;
  282.     myGroupPosition = ::Q3Group_AddObject(myLightList, myFillLight);
  283.     if ( myGroupPosition == 0 )
  284.         goto bail;
  285.  
  286.     ::Q3Object_Dispose( myAmbientLight ) ;
  287.     ::Q3Object_Dispose( myPointLight ) ;
  288.     ::Q3Object_Dispose( myFillLight ) ;
  289.  
  290.     //    Done!
  291.     return ( myLightList );
  292.     
  293. bail:
  294.     //    If any of the above failed, then return nothing!
  295.     return ( nil );
  296. }
  297.  
  298. //------------------------------------------------------------------------------------
  299. // MyAddShaderToGroup:
  300. //------------------------------------------------------------------------------------
  301. // attach a shader to the group
  302.  
  303. TQ3Status MyAddShaderToGroup( TQ3GroupObject group )
  304. {
  305.     TQ3ShaderObject    illuminationShader = ::Q3PhongIllumination_New();
  306.     if (illuminationShader == NULL)
  307.         return (kQ3Failure);
  308.  
  309.     ::Q3Group_AddObject(group, illuminationShader);
  310.     ::Q3Object_Dispose(illuminationShader);
  311.     return(kQ3Success);
  312. }
  313.  
  314. //------------------------------------------------------------------------------------
  315. // MyReadModelFromFile:
  316. //----------------------------------------------------------------------------------
  317. // read model from file object into the supplied group
  318.  
  319. TQ3Status MyReadModelFromFile( TQ3FileObject theFile,TQ3GroupObject myGroup)
  320. {    
  321.     if(theFile != NULL) {
  322.     
  323.         TQ3Object            myTempObj ;
  324.         TQ3Boolean            isEOF ;
  325.                 
  326.     
  327.         // read objects from the file
  328.         do {
  329.         
  330.             myTempObj = ::Q3File_ReadObject( theFile );
  331.             
  332.             if( myTempObj != NULL ) {
  333.                 // we only want the object in our main group if we can draw it
  334.                 if ( ::Q3Object_IsDrawable( myTempObj) ) 
  335.                     ::Q3Group_AddObject( myGroup, myTempObj ) ;
  336.                 
  337.                 // we either added the object to the main group, or we don't care
  338.                 // so we can safely dispose of the object
  339.                 ::Q3Object_Dispose( myTempObj ) ;
  340.             }
  341.             
  342.             // check to see if we reached the end of file yet
  343.             isEOF = ::Q3File_IsEndOfFile( theFile );
  344.             
  345.         } while (isEOF == kQ3False);    
  346.     }
  347.     
  348.     if( myGroup != NULL )
  349.         return kQ3Success ;
  350.     else
  351.         return kQ3Failure ;
  352. }
  353. //------------------------------------------------------------------------------------
  354. // MyGetNewFile:
  355. //------------------------------------------------------------------------------------
  356. TQ3FileObject 
  357. MyGetNewFile( PluginInstance* This)
  358.  
  359. {
  360.         TQ3StorageObject    myStorageObj;
  361.         TQ3FileObject myFileObj;
  362.         
  363.         myStorageObj = ::Q3HandleStorage_New(This->fBuffer,This->fBufferLength) ;
  364.         if (myStorageObj == NULL) 
  365.         {
  366.             return NULL;
  367.         }
  368.  
  369.         myFileObj = ::Q3File_New() ;
  370.         if (myFileObj == NULL) 
  371.         {
  372.             ::Q3Object_Dispose(myStorageObj) ;
  373.             return NULL;
  374.         }
  375.  
  376.         // Set the storage for the file object
  377.         ::Q3File_SetStorage(myFileObj, myStorageObj) ;
  378.         ::Q3Object_Dispose(myStorageObj) ;
  379.         
  380.         return myFileObj;
  381. }
  382.  
  383. //------------------------------------------------------------------------------------
  384. // MyNewModelFromBuffer:
  385. //------------------------------------------------------------------------------------
  386. // read model from buffer into the supplied group
  387. //----------------------------------------------------------------------------------
  388.  
  389. TQ3GroupObject 
  390. MyNewModelFromBuffer(PluginInstance* This)
  391. {
  392.     TQ3GroupObject        myGroup = NULL ;
  393.     TQ3Boolean            isText = kQ3False ;
  394.     TQ3FileMode            myFileMode = 0;
  395.     TQ3FileObject        theFile;
  396.     TQ3Status            myStatus;
  397.     
  398.     //    Create a ordered group for the complete model.
  399.     if ((myGroup = ::Q3DisplayGroup_New()) == NULL )
  400.         return NULL;
  401.         
  402.     MyAddShaderToGroup( myGroup ) ;
  403.     
  404.     theFile = MyGetNewFile( This ) ;
  405.     if (theFile == NULL)
  406.     {
  407.         ::Q3Object_Dispose(myGroup);
  408.         return  NULL ;        
  409.     }    
  410.  
  411.     // Open the file object
  412.     myStatus = ::Q3File_OpenRead( theFile, NULL ) ;
  413.     if (myStatus  != kQ3Success) 
  414.     {
  415.         ::Q3Object_Dispose(theFile);
  416.         ::Q3Object_Dispose(myGroup);
  417.         return  NULL ;        
  418.     }    
  419.  
  420.     if( MyReadModelFromFile( theFile, myGroup ) == 0)
  421.         DebugStr("\pMetafile data read is null") ;
  422.  
  423.     // close and dispose of the file object
  424.     ::Q3File_Close(theFile);            
  425.     ::Q3Object_Dispose(theFile);
  426.     
  427.     return myGroup ;
  428. }
  429.  
  430. //------------------------------------------------------------------------------------
  431. // SubmitScene:
  432. //------------------------------------------------------------------------------------
  433. // Submit the scene for rendering/fileIO and picking
  434. TQ3Status SubmitScene( PluginInstance* theDocument ) 
  435. {        
  436.     TQ3Vector3D                globalScale;
  437.     TQ3Vector3D                globalTranslate;
  438.     
  439.     globalScale.x = globalScale.y = globalScale.z = theDocument->fGroupScale;
  440.     globalTranslate = *(TQ3Vector3D *)&theDocument->fGroupCenter;
  441.     ::Q3Vector3D_Scale(&globalTranslate, -1, &globalTranslate);
  442.     ::Q3Style_Submit(theDocument->fInterpolation, theDocument->fView);
  443.     ::Q3Style_Submit(theDocument->fBackFacing , theDocument->fView);
  444.     ::Q3Style_Submit(theDocument->fFillStyle, theDocument->fView);
  445.         
  446.     ::Q3MatrixTransform_Submit( &theDocument->fRotation, theDocument->fView);
  447.         
  448.     ::Q3ScaleTransform_Submit(&globalScale, theDocument->fView);
  449.     ::Q3TranslateTransform_Submit(&globalTranslate, theDocument->fView);
  450.     ::Q3DisplayGroup_Submit( theDocument->fModel, theDocument->fView);
  451.     
  452.     return kQ3Success ;
  453. }
  454.  
  455. //------------------------------------------------------------------------------------
  456. // GetDocumentGroupBoundingBox:
  457. //------------------------------------------------------------------------------------
  458. TQ3Status GetDocumentGroupBoundingBox( 
  459.     PluginInstance*        theDocument,
  460.     TQ3BoundingBox         *viewBBox)
  461. {
  462.     TQ3Status        status;
  463.     TQ3ViewStatus    viewStatus ;
  464.     
  465.     status = ::Q3View_StartBoundingBox( theDocument->fView, kQ3ComputeBoundsApproximate );
  466.     do {
  467.         status = SubmitScene( theDocument ) ;
  468.     } while((viewStatus = ::Q3View_EndBoundingBox( theDocument->fView, viewBBox )) == kQ3ViewStatusRetraverse );
  469.     return status ;
  470. }
  471.  
  472. //------------------------------------------------------------------------------------
  473. // GetGroupBBox:
  474. //------------------------------------------------------------------------------------
  475. void GetGroupBBox(
  476.     PluginInstance*        theDocument,
  477.     TQ3BoundingBox         *viewBBox)
  478. {
  479.     TQ3Point3D                     from     = { 0.0, 0.0, 1.0 };
  480.     TQ3Point3D                     to         = { 0.0, 0.0, 0.0 };
  481.     TQ3Vector3D                 up         = { 0.0, 1.0, 0.0 };
  482.     
  483.     float                         fieldOfView = .52359333333;
  484.     float                         hither         =  0.5;
  485.     float                         yon         =  1.5;
  486.     TQ3GroupObject                mainGroup = theDocument->fModel ;
  487.  
  488.     TQ3Status                    status;
  489.     
  490. #ifdef BETA_1_BUILD
  491.     ::Q3View_StartBounds( theDocument->fView );
  492.  
  493.     status = ::Q3DisplayGroup_BoundingBox(mainGroup, 
  494.                                         viewBBox, 
  495.                                         kQ3ComputeBoundsApproximate,
  496.                                          viewObject);
  497.  
  498.     ::Q3View_EndBounds( theDocument->fView );
  499. #else
  500.     status = GetDocumentGroupBoundingBox( theDocument , viewBBox) ;
  501. #endif
  502.                                         
  503.     //
  504.     //  If we have a point model, then the "viewBBox" would end up
  505.     //  being a "singularity" at the location of the point.  As
  506.     //  this bounding "box" is used in setting up the camera spec,
  507.     //  we get bogus input into Escher.
  508.     
  509.     {
  510.          float        xSize, ySize, zSize;
  511.         
  512.         xSize = viewBBox->max.x - viewBBox->min.x;
  513.         ySize = viewBBox->max.y - viewBBox->min.y;
  514.         zSize = viewBBox->max.z - viewBBox->min.z;
  515.  
  516.         if (xSize <= kQ3RealZero &&
  517.             ySize <= kQ3RealZero &&
  518.             zSize <= kQ3RealZero) {
  519.             
  520.             viewBBox->max.x += 0.0001;
  521.             viewBBox->max.y += 0.0001;
  522.             viewBBox->max.z += 0.0001;
  523.             
  524.             viewBBox->min.x -= 0.0001;
  525.             viewBBox->min.y -= 0.0001;
  526.             viewBBox->min.z -= 0.0001;
  527.         }
  528.     }
  529. }
  530.  
  531. //------------------------------------------------------------------------------------
  532. // AdjustCamera:
  533. //------------------------------------------------------------------------------------
  534. TQ3Point3D AdjustCamera(
  535.     PluginInstance*        theDocument,
  536.     short                winWidth,
  537.     short                winHeight)
  538. {
  539.     float                         fieldOfView;
  540.     float                         hither;
  541.     float                         yon;
  542.     TQ3CameraPlacement            placement;
  543.     TQ3CameraRange                range;
  544.     TQ3BoundingBox                 viewBBox;
  545.     long                         fromAxis;    
  546.     float                         maxDimension;
  547.      float                        xSize, ySize, zSize;
  548.     float                        weights[2] = { 0.5, 0.5 };
  549.     TQ3Point3D                    points[2];
  550.     TQ3Vector3D                     viewVector;
  551.     TQ3Vector3D                    normViewVector;
  552.     TQ3Vector3D                    eyeToFrontClip;
  553.     TQ3Vector3D                    eyeToBackClip;
  554.     float                        viewDistance;
  555.     TQ3Vector3D                    diagonalVector;
  556.     float                        ratio;
  557.     TQ3CameraObject                camera;
  558.     
  559.     TQ3ViewObject                theView = theDocument->fView ;
  560.     
  561.     TQ3Point3D                    *documentGroupCenter = &theDocument->fGroupCenter ;
  562.     float                        *documentGroupScale  = &theDocument->fGroupScale ;
  563.  
  564.     ::Q3View_GetCamera( theView, &camera);
  565.     GetGroupBBox( theDocument, &viewBBox);
  566.  
  567.     /*
  568.      *  If we have a point model, then the "viewBBox" would end up
  569.      *  being a "singularity" at the location of the point.  As
  570.      *  this bounding "box" is used in setting up the camera spec,
  571.      *  we get bogus input into Escher.
  572.      */
  573.     xSize = viewBBox.max.x - viewBBox.min.x;
  574.     ySize = viewBBox.max.y - viewBBox.min.y;
  575.     zSize = viewBBox.max.z - viewBBox.min.z;
  576.  
  577.     if (xSize <= kQ3RealZero &&
  578.         ySize <= kQ3RealZero &&
  579.         zSize <= kQ3RealZero)  {
  580.         viewBBox.max.x += 0.0001;
  581.         viewBBox.max.y += 0.0001;
  582.         viewBBox.max.z += 0.0001;
  583.         
  584.         viewBBox.min.x -= 0.0001;
  585.         viewBBox.min.y -= 0.0001;
  586.         viewBBox.min.z -= 0.0001;
  587.     }
  588.  
  589.     points[0] = viewBBox.min;
  590.     points[1] = viewBBox.max;
  591.  
  592.     ::Q3Point3D_AffineComb(points, weights, 2, documentGroupCenter);
  593.  
  594.     /*
  595.      *  The "from" point is on a vector perpendicular to the plane
  596.      *  in which the bounding box has greatest dimension.  As "up" is
  597.      *  always in the positive y direction, look at x and z directions.
  598.      */
  599.     xSize = viewBBox.max.x - viewBBox.min.x;
  600.     zSize = viewBBox.max.z - viewBBox.min.z;
  601.     
  602.     if (xSize > zSize) {
  603.         fromAxis = kQ3AxisZ;
  604.     } else {
  605.         fromAxis = kQ3AxisX;
  606.     }
  607.  
  608.     /*
  609.      *  Compute the length of the diagonal of the bounding box.
  610.      *
  611.      *  The hither and yon planes are adjusted so that the
  612.       *  diagonal of the bounding box is 7/8 the size of the
  613.       *  minimum dimension of the view frustum. The diagonal is used instead
  614.       *  of the maximum size (in x, y, or z) so that when you rotate
  615.       *  the object, the corners don't get clipped out.
  616.       */
  617.     ::Q3Point3D_Subtract(
  618.         &viewBBox.max,
  619.         &viewBBox.min,
  620.         &diagonalVector);
  621.  
  622.     maxDimension    =    ::Q3Vector3D_Length(&diagonalVector);
  623.     maxDimension    *=    8.0 / 7.0;
  624.     
  625.     ratio = 1.0 / maxDimension;
  626.             
  627.     *documentGroupScale = ratio;
  628.     
  629.     ::Q3Camera_GetPlacement(camera, &placement);
  630.  
  631.     ::Q3Point3D_Subtract(
  632.         &placement.cameraLocation,
  633.         &placement.pointOfInterest,
  634.         &viewVector);
  635.         
  636.     viewDistance = ::Q3Vector3D_Length(&viewVector);
  637.     
  638.     ::Q3Vector3D_Normalize(&viewVector, &normViewVector);
  639.     
  640.     ::Q3Vector3D_Scale(&normViewVector, 
  641.                      viewDistance - ratio * maxDimension/2.0,
  642.                      &eyeToFrontClip);
  643.                     
  644.     ::Q3Vector3D_Scale(&normViewVector, 
  645.                     viewDistance + ratio * maxDimension/2.0,
  646.                     &eyeToBackClip);
  647.  
  648.     hither     = ::Q3Vector3D_Length(&eyeToFrontClip);
  649.     yon     = ::Q3Vector3D_Length(&eyeToBackClip);
  650.     
  651.     fieldOfView = 2 * atan((ratio * maxDimension/2.0)/hither);
  652.  
  653.     range.hither                 = hither;
  654.     range.yon                     = yon;
  655.  
  656.     ::Q3Camera_SetRange(camera, &range);
  657.  
  658.     ::Q3ViewAngleAspectCamera_SetFOV(
  659.         camera, fieldOfView);
  660.  
  661.     ::Q3ViewAngleAspectCamera_SetAspectRatio(
  662.         camera, (float) winWidth / (float) winHeight);
  663.  
  664.     ::Q3Object_Dispose(camera);
  665.     
  666.     return( *documentGroupCenter );
  667. }
  668.  
  669. //------------------------------------------------------------------------------------
  670. // NameFromType:
  671. //------------------------------------------------------------------------------------
  672. char* NameFromQ3Type(char* nm, TQ3ObjectType typ)
  673. {
  674.     BlockMove(&typ, nm, 4);
  675.     nm[4] = 0;
  676.     return nm;
  677. }
  678.  
  679. //------------------------------------------------------------------------------------
  680. // TypeNameOfQ3Object:
  681. //------------------------------------------------------------------------------------
  682. char* TypeNameFromQ3Obj(char* nm, TQ3Object obj)
  683. {
  684.     TQ3ObjectType    typ = ::Q3Object_GetLeafType(obj);
  685.     
  686.     return NameFromQ3Type(nm,typ);
  687. }
  688. //------------------------------------------------------------------------------------
  689. // DocumentDraw3DData:
  690. //------------------------------------------------------------------------------------
  691.  
  692. // assumes the port is set up before being called
  693. TQ3Status DocumentDraw3DData( PluginInstance* theDocument )
  694. {
  695.     TQ3Status                 theStatus = kQ3Failure;    
  696.     
  697.     if (theDocument->fBusy )    // Do not draw if we are not done.
  698.     {
  699.         //NPN_Status(theDocument, "Tried to draw before data finished loading.");
  700.         return kQ3Failure;
  701.     }
  702.     
  703.     if (theDocument->fModel == NULL)    // Do not draw if nothing's there.
  704.     {
  705.         //NPN_Status(theDocument, "Tried to draw, but no data received.");
  706.         return kQ3Failure;
  707.     }
  708.     
  709.     ::Q3View_StartRendering(theDocument->fView) ;
  710.     do {
  711.         theStatus = SubmitScene( theDocument ) ;
  712.  
  713.     } while (::Q3View_EndRendering(theDocument->fView) == kQ3ViewStatusRetraverse );
  714.  
  715.     return theStatus ;
  716. }
  717.  
  718.